#!/usr/bin/python
# vim: set fileencoding=utf-8 :

import sys
import unittest
import trace
import random

from hexaInt import aInt
from hexaPosInt import posInt
from hexaCongruent import congruentRelation as cR
from hexaLinCombi import linearCombination as lC

class TestCaseVectors() :

    def CongruentRandom(self, a=None, b=None, n=None, q=None) :
        """ Returns a random true congruent relation
        a ≡ b (mod n)
        Parameters:
            'a' if not supplied it is calculated randomly.
            'b' if not supplied it is calculated as b = a + q * n.
            'n' if not supplied it is calculated randomly.
            'q' if not supplied it is calculated randomly.
        """
        random.seed()
        if n == None :
            n = posInt(random.randint(1,1000))
        if q == None :
            q = posInt(random.randint(1,1000))
        if a == None :
            a = aInt(random.randint(-1000000,1000000))
        if b == None :
            b = aInt(a + q * n)
        return cR(a, b, n)

    def CongruentRandomNoOk(self) :
        """ Returns a random false congruent relation
        a !≡ b (mod n)
        Parameters:
            'a' if not supplied it is calculated randomly.
            'b' if not supplied it is calculated randomly.
            'n' if not supplied it is calculated randomly.
            'q' if not supplied it is calculated randomly.
        """
        random.seed()
        n = posInt(random.randint(1,1000))
        q = posInt(random.randint(1,1000))
        a = aInt(random.randint(-1000000,1000000))
        b = aInt(random.randint(-1000000,1000000))
        return cR(a, b, n)

    def Print(self, a, msg) :
        """ Prints 'msg' and the congruent relation 'a'.
        """
        print msg, str(a)

    def Vector01(self) :
        """ Generate Test Vector.
        Returns :
            'v1' Congruent relation modulus 'n'.
            'v2' Congruent relation modulus 'n'.
            'v3' False Congruente relation random modulus.
        """
        v1 = self.CongruentRandom()
        v2 = self.CongruentRandom(n = v1.n)
        v3 = self.CongruentRandomNoOk()
        return [v1, v2, v3]

    def Vector02(self) :
        """ Generate Test Vector.
        v1
        -860490 ≡ -859601 mod(1)
        v2
        261007 ≡ 262004 mod(1)
        v3
        -373929 ≡ -671974 mod(1)
        """
        a0 = aInt(-860490)
        a1 = aInt(-859601)
        b0 = aInt(261007)
        b1 = aInt(262004)
        c0 = aInt(-373929)
        c1 = aInt(-671974)
        n = posInt(1)
        v1 = cR(a0, a1, n)
        v2 = cR(b0, b1, n)
        v3 = cR(c0, c1, n)
        return [v1, v2, v3]

    def Vector03(self, p) :
        """ Generate Test Vector.
        Returns a list of len 'p' of PosInt.
        Parameters:
            'p' List size.
        """
        random.seed()
        l = []
        for q in range(p) :
            l.append(posInt((random.randint(1,1000))))
        return l

    def Vector04(self, n=None, a=None) :
        """ Generate Test Vector.
        Returns the Congruent Relation a ≡ 1 (mod n)
        Parameters:
            'a' if not supplied it is calculated randomly.
            'n' if not supplied it is calculated randomly.
        """
        random.seed()
        if n == None :
            n = posInt(random.randint(1,1000))
        if a == None :
            a = aInt(random.randint(-1000000,1000000))
        b = aInt(1)
        return cR(a, b, n)


class TestCase01(unittest.TestCase):
    """ Test Case 01
    Test the Properties of Congruent Relations.
    """

    def setUp(self):
        print self.id()
        print self.shortDescription()
        self.v = TestCaseVectors()
        [self.v1, self.v2, self.v3] = self.v.Vector01()
        [self.r0, self.r1, self.r2] = self.v.Vector03(3)
        self.v.Print(self.v1, "Congruent Relation 'v1'")
        self.v.Print(self.v2, "Congruent Relation 'v2'")
        self.v.Print(self.v3, "Congruent Relation 'v3'")

    def tearDown(self):
        print ">>>>>>>"

    def testStep010(self) :
        """ Test Definition and Proposition 1.3.2
        """
        self.assertTrue(self.v1.a.isInteger(), '"v1.a is not integer')
        self.assertTrue(self.v1.b.isInteger(), '"v1.b is not integer')
        self.assertTrue(self.v2.a.isInteger(), '"v2.a is not integer')
        self.assertTrue(self.v2.b.isInteger(), '"v2.b is not integer')
        self.assertTrue(self.v3.a.isInteger(), '"v3.a is not integer')
        self.assertTrue(self.v3.b.isInteger(), '"v3.b is not integer')
        self.assertTrue(self.v1.n.isPositiveInteger(), 'modulus is not positive')
        self.assertTrue(self.v1.isCongruentRelation(), 'v1 is not a Congruent Relation')
        self.assertTrue(self.v2.isCongruentRelation(),  'v2 is not a Congruent Relation')
        self.assertFalse(self.v3.isCongruentRelation(),  'v3 is a Congruent Relation')

    def testStep020(self) :
        pass

    def testStep030(self) :
        "Test for Proposition 1.3.3 addition"
        self.w = self.v1 + self.v2
        self.assertTrue(self.w.isCongruentRelation(), 'Addition v1 & v2 is not congruent')

    def testStep040(self) :
        "Test for Proposition 1.3.3 offset"
        self.w = self.v1 + self.r0
        self.assertTrue(self.w.isCongruentRelation(), 'Offset Addition v1 is not congruent')

    def testStep050(self) :
        "Test for Proposition 1.3.3 substraction"
        self.w = self.v1 - self.v2
        self.assertTrue(self.w.isCongruentRelation(), 'Substraction v1 & v2 is not congruent')

    def testStep060(self) :
        "Test for Proposition 1.3.3 offset substraction"
        self.w = self.v1 - self.r1
        self.assertTrue(self.w.isCongruentRelation(), 'Offset Substraction v1 v2 is not congruent')

    def testStep070(self) :
        "Test for Proposition 1.3.3 multiplication"
        self.w = self.v1 * self.v2
        self.assertTrue(self.w.isCongruentRelation(), 'Multiplication v1 & v2 is not congruent')

    def testStep080(self) :
        "Test for Proposition 1.3.3 slope"
        self.w = self.v1 * self.r2
        self.assertTrue(self.w.isCongruentRelation(), 'Slope v1 is not congruent')

    def runTest(self) :
        self.testStep010()
        self.testStep020()
        self.testStep030()
        self.testStep040()
        self.testStep050()
        self.testStep060()
        self.testStep070()
        self.testStep080()

class TestCase02(unittest.TestCase):
    """ Test Case 02
    """

    def setUp(self):
        print self.id()
        print self.shortDescription()
        self.v = TestCaseVectors()
        [self.v1, self.v2, self.v3] = self.v.Vector02()
        [self.r0, self.r1, self.r2] = self.v.Vector03(3)
        self.v.Print(self.v1, "Congruent Relation 'v1'")
        self.v.Print(self.v2, "Congruent Relation 'v2'")
        self.v.Print(self.v3, "Congruent Relation 'v3'")

    def tearDown(self):
        print ">>>>>>>"

    def testStep005(self) :
        "Test Initialization"
        pass

    def testStep010(self) :
        "Test Definition and Proposition 1.3.2"
        self.assertTrue(self.v1.a.isInteger(), '"v1.a is not integer')
        self.assertTrue(self.v1.b.isInteger(), '"v1.b is not integer')
        self.assertTrue(self.v2.a.isInteger(), '"v2.a is not integer')
        self.assertTrue(self.v2.b.isInteger(), '"v2.b is not integer')
        self.assertTrue(self.v3.a.isInteger(), '"v3.a is not integer')
        self.assertTrue(self.v3.b.isInteger(), '"v3.b is not integer')
        self.assertTrue(self.v1.n.isPositiveInteger(), 'modulus is not positive')
        self.assertTrue(self.v1.isCongruentRelation(), 'v1 is not a Congruent Relation')
        self.assertTrue(self.v2.isCongruentRelation(),  'v2 is not a Congruent Relation')
        self.assertTrue(self.v3.isCongruentRelation(),  'v3 is not a Congruent Relation')

    def testStep020(self) :
        pass

    def testStep030(self) :
        "Test for Proposition 1.3.3 addition"
        self.w = self.v1 + self.v2
        self.assertTrue(self.w.isCongruentRelation())

    def testStep040(self) :
        "Test for Proposition 1.3.3 offset"
        self.w = self.v1 + self.r0
        self.assertTrue(self.w.isCongruentRelation())

    def testStep050(self) :
        "Test for Proposition 1.3.3 substraction"
        self.w = self.v1 - self.v2
        self.assertTrue(self.w.isCongruentRelation())

    def testStep060(self) :
        "Test for Proposition 1.3.3 offset substraction"
        self.w = self.v1 - self.r1
        self.assertTrue(self.w.isCongruentRelation())

    def testStep070(self) :
        "Test for Proposition 1.3.3 multiplication"
        self.w = self.v1 * self.v2
        self.assertTrue(self.w.isCongruentRelation())

    def testStep080(self) :
        "Test for Proposition 1.3.3 slope"
        self.w = self.v1 * self.r2
        self.assertTrue(self.w.isCongruentRelation())

    def runTest(self) :
        self.testStep005()
        self.testStep010()
        self.testStep020()
        self.testStep030()
        self.testStep040()
        self.testStep050()
        self.testStep060()
        self.testStep070()
        self.testStep080()

class TestCase03(unittest.TestCase) :
    """Test Case No. 03
    """
    def setUp(self):
        print self.id()
        print self.shortDescription()
        self.v = TestCaseVectors()
        self.v1 = self.v.Vector04()
        self.k = self.v.Vector03(2)
        self.v.Print(self.v1, "Congruent Relation 'ab = 1 (mod n)'")

    def tearDown(self):
        print ">>>>>>>"

    def testStep005(self) :
        "Test Initialization"
        pass

    def testStep010(self) :
        "Test Proposition 1.3.4"
        [b, y] = self.v1.Proposition134()
        print "b = ", str(b)
        if b != None :
            self.w = cR(self.v1.a * b, self.v1.b, self.v1.n)
            self.v.Print(self.w, "Congruent Relation 'ab = 1 (mod n)'")
            self.assertTrue(self.w.isCongruentRelation())

    def runTest(self) :
        self.testStep010()

def main() :
    ut01 = TestCase01()
    ut02 = TestCase02()
    ut03 = TestCase03()
    sut = unittest.TestSuite()
    sut.addTest(ut01)
    sut.addTest(ut02)
    sut.addTest(ut03)
    stream = open('UtResults.log', 'w')
    sr = unittest.TextTestRunner(stream, True, 1)

    print "No. of TestCases: "
    print sut.countTestCases()
    sr.run(sut)

# create a Trace object, telling it what to ignore, and whether to
# do tracing or line-counting or both.
tracer = trace.Trace( ignoredirs=[sys.prefix, sys.exec_prefix], trace=0, count=1)

# run the new command using the given tracer
tracer.run('main()')

# make a report, placing output in /tmp
r = tracer.results()
r.write_results(show_missing=True, summary=True, coverdir='./')

